/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * File Name          : freertos.c
  * Description        : Code for freertos applications
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/**
 * 这一层做的事情就是,创建线程、函数适配、封装系统级接口给下层,然后把所有接口整合一起通过线程函数传过去
 */
/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "iic_hal.h"
#include "bsp_temp_humi_handler.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define AHT_CLK_ENABLE __HAL_RCC_GPIOB_CLK_ENABLE()
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */
iic_bus_t iic_bus_instance = {
  .IIC_SDA_PORT = GPIOB,
  .IIC_SDA_PIN  = GPIO_PIN_13,
  .IIC_SCL_PORT = GPIOB,
  .IIC_SCL_PIN  = GPIO_PIN_14
};
/* USER CODE END Variables */
/* Definitions for defaultTask */
osThreadId_t defaultTaskHandle;
const osThreadAttr_t defaultTask_attributes = {
  .name = "defaultTask",
  .stack_size = 128 * 4,
  .priority = (osPriority_t) osPriorityNormal,
};

osThreadId_t tempHumiTaskHandle;
const osThreadAttr_t tempHumiTask_attributes = {
  .name = "tempHumiTask",
  .stack_size = 128 * 4,
  .priority = (osPriority_t) osPriorityBelowNormal,
};
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */

//APP层定义回调函数,应该怎么操作
void temp_humi_callback(float *temp, float * humi)
{
  printf("回调函数得到的温度:%f,湿度:%f\r\n", *temp, *humi);
}

/*
 *对带了结构体指针的函数进行适配器转换,
 *这一步的关键点是把传给driver层、handler层的函数形参用void*替换掉,
 *可以认为是上层在传递函数指针的时候如果有底层没有的结构体，就需要用这种适配器进行解耦
 *所以函数是否需要进行适配器转换的标准就是,形参是否有底层没有申明的结构体
*/
int8_t iic_init_myown(void * iic_bus)
{
  AHT_CLK_ENABLE;
  IICInit(&iic_bus_instance);
  return 0;
}

int8_t iic_deinit_myown(void * iic_bus)
{
  return 0;
}
void iic_start_myown(void * iic_bus)
{
  IICStart(&iic_bus_instance);
}

void iic_stop_myown(void * iic_bus)
{
  IICStop(&iic_bus_instance);
}

int8_t iic_wait_ack_myown(void * iic_bus)
{
  IICWaitAck(&iic_bus_instance);
  return 0;
}

void iic_send_ack_myown(void * iic_bus)
{
  IICSendAck(&iic_bus_instance);
}

void iic_send_no_ack_myown(void * iic_bus)
{
  IICSendNotAck(&iic_bus_instance);
}

void iic_send_byte_myown(void * iic_bus, uint8_t data)
{
  IICSendByte(&iic_bus_instance, data);
}

uint8_t iic_receive_byte_myown(void * iic_bus)
{
  return IICReceiveByte(&iic_bus_instance);
}
void os_delay(uint32_t ms)
{
  osDelay(ms);
}

//1. 当需要返回多个值时,就会把返回值移到形参
//2. 当函数的返回是正常变量,形参就是一级指针
//3. 当函数返回值是一级指针时,形参就是二级指针,这里需要返回队列的句柄,是个一级指针,所以形参用二级指针
int8_t queue_create(uint32_t item_num, uint32_t item_size,void **queue_handle)
{
  *queue_handle = osMessageQueueNew(item_num, item_size, NULL);
  if(NULL == *queue_handle)
  {
    return -1;
  }else
  {
    return 0;
  }
}
//写队列
int8_t queue_put(void *queue_handle, void *item, uint32_t timeout)
{
  return osMessageQueuePut(queue_handle, item, NULL, timeout);
}
//读队列
int8_t queue_get(void *queue_handle, void *msg,  uint32_t timeout)
{
  return osMessageQueueGet(queue_handle, msg, NULL, timeout);
}
/* USER CODE END FunctionPrototypes */

void StartDefaultTask(void *argument);

void StartTempHumiTask(void *argument);

void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */

/**
  * @brief  FreeRTOS initialization
  * @param  None
  * @retval None
  */
void MX_FREERTOS_Init(void) {
  /* USER CODE BEGIN Init */
  static iic_driver_interface_t iic_driver_interface = {
    .pfiic_init         = iic_init_myown,
    .pfiic_deinit       = iic_deinit_myown,
    .pfiic_start        = iic_start_myown,
    .pfiic_stop         = iic_stop_myown,
    .pfiic_wait_ack     = iic_wait_ack_myown,
    .pfiic_send_no_ack  = iic_send_no_ack_myown,
    .pfiic_send_byte    = iic_send_byte_myown,
    .pfiic_receive_byte = iic_receive_byte_myown,
    .pfiic_send_ack     = iic_send_ack_myown
  };

  static yield_interface_t yield_interface = {
    .os_delay_ms = os_delay
  };

  static irq_interface_t irq_interface = {
    .pftaskENTER_CRITICAL = vPortEnterCritical,
    .pftaskEXIT_CRITICAL  = vPortExitCritical
  };
  
  static temp_humi_handler_os_interface_t os_interface = {
    .pfget_tick     = HAL_GetTick,
    .pfos_delay_ms  = os_delay,
    .pfqueue_create = queue_create,
    .pfqueue_put    = queue_put,
    .pfqueue_get    = queue_get
  };

  static temp_humi_handler_all_input_arg_t all_argus = {
    .iic_driver_interface           = &iic_driver_interface,
    .irq_interface                  = &irq_interface,
    .yield_interface                = &yield_interface,
    .temp_humi_handler_os_interface = &os_interface
  };
  /* USER CODE END Init */

  /* USER CODE BEGIN RTOS_MUTEX */
  /* add mutexes, ... */
  /* USER CODE END RTOS_MUTEX */

  /* USER CODE BEGIN RTOS_SEMAPHORES */
  /* add semaphores, ... */
  /* USER CODE END RTOS_SEMAPHORES */

  /* USER CODE BEGIN RTOS_TIMERS */
  /* start timers, add new ones, ... */
  /* USER CODE END RTOS_TIMERS */

  /* USER CODE BEGIN RTOS_QUEUES */
  /* add queues, ... */
  /* USER CODE END RTOS_QUEUES */

  /* Create the thread(s) */
  /* creation of defaultTask */

  defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);

  defaultTaskHandle = osThreadNew(StartTempHumiTask, (void*)&all_argus, &tempHumiTask_attributes);

  /* USER CODE BEGIN RTOS_THREADS */
  /* add threads, ... */
  /* USER CODE END RTOS_THREADS */

  /* USER CODE BEGIN RTOS_EVENTS */
  /* add events, ... */
  /* USER CODE END RTOS_EVENTS */

}

/* USER CODE BEGIN Header_StartDefaultTask */
/**
  * @brief  Function implementing the defaultTask thread.
  * @param  argument: Not used
  * @retval None
  */
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void *argument)
{
  /* USER CODE BEGIN StartDefaultTask */
  float temp = 0;
  float humi = 0;
  temp_humi_handler_event_t event = {
    .temp = &temp,
    .humi = &humi,
    .lifetime = 50,
    .timestamp = HAL_GetTick(),
    .pfcallback = temp_humi_callback,
    .type       = TEMP_HUMI_EVENT_DATA_TYPE_BOTH
  };
 
  
  /* Infinite loop */
  for(;;)
  {
    event.timestamp = HAL_GetTick();
    printf("发送一次消息 \r\n");
    bsp_temp_humi_read(&event);
    osDelay(1000);
  }
  /* USER CODE END StartDefaultTask */
}

/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */
__weak void StartTempHumiTask(void *argument)
{
  for(;;)
  {
    osDelay(1);
  }
}
/* USER CODE END Application */

